package com.wiz.web.service.impl;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.primitives.Doubles;
import com.wiz.common.util.DecimalUtil;
import com.wiz.common.util.PRUtil;
import com.wiz.data.vo.to.MabDataTO;
import com.wiz.log.NettyInfoRecord;
import com.wiz.web.dao.mapper.AccountMapper;
import com.wiz.web.dao.mapper.AuthorityMapper;
import com.wiz.web.dao.mapper.HqStationMapper;
import com.wiz.web.dao.mapper.MemberMapper;
import com.wiz.web.manager.ServiceManager;
import com.wiz.web.service.AccountService;
import com.wiz.web.service.AuthorityService;
import com.wiz.web.vo.TransimissionVO;
import com.wiz.web.vo.criteria.AuthorityCriteria;
import com.wiz.web.vo.criteria.FpCriteria;
import com.wiz.web.vo.criteria.MemberCriteria;
import com.wiz.web.vo.to.AdminTO;
import com.wiz.web.vo.to.AuthorityTO;
import com.wiz.web.vo.to.FpTO;
import com.wiz.web.vo.to.MemberGradeTO;
import com.wiz.web.vo.to.MemberTO;
import com.wiz.web.vo.to.PRConfigTO;
import com.wiz.web.vo.type.AuthType;
import com.wiz.web.vo.type.AuthorityType;
import com.wiz.web.vo.type.CompanyType;


@Service("authorityService")
public class AuthorityServiceImpl extends BasicServiceImpl implements AuthorityService{
	private transient final Logger log = LoggerFactory.getLogger(getClass());
	
	@Resource
	private MemberMapper memberMapper;
	@Resource
	private AuthorityMapper authorityMapper;
	@Resource
	private HqStationMapper hqStationMapper;
	@Resource
	private AccountMapper accountMapper;
	@Resource
	private AccountService accountService;
	
	
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)
	public void handleResquest(String stationId,MabDataTO mabTO,ServiceManager serviceManager) {
		String dataType = mabTO.getWiz_1_dataType();
		if(dataType.endsWith("1")){//加油授权确认接收
			AuthorityCriteria criteria = new AuthorityCriteria();
			criteria.setAuthorityId(mabTO.getWiz_14_authorityId());
			int status = Integer.parseInt(mabTO.getWiz_60_status());
			criteria.setStatus(status);
			try {
				thawAmount(criteria);
			} catch (Exception e) {
				e.printStackTrace();
				//不删除询问任务
				return;
			}
			serviceManager.removeTransmissionTask(stationId, criteria.getAuthorityId());
		}else if(dataType.endsWith("2")){//积分授权确认接收
			AuthorityCriteria criteria = new AuthorityCriteria();
			criteria.setAuthorityId(mabTO.getWiz_14_authorityId());
			int status = Integer.parseInt(mabTO.getWiz_60_status());
			criteria.setStatus(status);
			try {
				authorityMapper.updateFuellingAuthorityByCriteria(criteria);
			} catch (Exception e) {
				e.printStackTrace();
				//不删除询问任务
				return;
			}
		}
	}
	
	@Override
	public double getPointAuthority(AuthorityCriteria criteria){
		TransimissionVO vo = transMap.get(criteria.getFpId());//打开微信挂起线程开关
		if(vo != null){
			vo.setSwitchValue(1);
		}
		return -0.0007;
	}
	
	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)
	public double getFrozenMoney(AuthorityCriteria criteria, AuthorityTO to) throws Exception {
		to.setAuthorityId("S"+System.currentTimeMillis()+getRandom(5));//生成主键
		to.setClientUUId(criteria.getClientUUId());
		to.setAuthorityType(AuthorityType.S.getId());
		to.setFpId(criteria.getFpId());
		to.setStationId(criteria.getStationId());
		to.setStatus(0);
		to.setType(AuthType.FUL.getId());
		return frozenAmount(to,criteria);
	}
	
	@Override
	public String getFuellingAuthority(double frozenAmount, String fpId, AuthorityTO to){
		TransimissionVO vo = transMap.get(fpId);//打开微信挂起线程开关,载体的值对应微信处返回的消息
		if(frozenAmount>0){
			if(vo != null){
				vo.setSwitchValue(1);
				vo.setMsg(RESPONSE_CODE_OK);
			}
			return returnResult(CODE_OK,STRING_OK,to);
		}else if(frozenAmount == -0.0001){
			if(vo != null){
				vo.setSwitchValue(2);
				vo.setMsg(RESPONSE_CODE_AUTHORITY_NO_ADMIN);
			}
			return RESPONSE_CODE_AUTHORITY_NO_ADMIN;
		}else if(frozenAmount == -0.0002){
			if(vo != null){
				vo.setSwitchValue(3);
				vo.setMsg(RESPONSE_CODE_INVALID_ADMIN);
			}
			return RESPONSE_CODE_INVALID_ADMIN;
		}else if(frozenAmount == -0.0003){
			if(vo != null){
				vo.setSwitchValue(4);
				vo.setMsg(RESPONSE_CODE_INVALID_MEMBER);
			}
			return RESPONSE_CODE_INVALID_MEMBER;
		}else if(frozenAmount == -0.0004){
			if(vo != null){
				vo.setSwitchValue(5);
				vo.setMsg(RESPONSE_CODE_AUTHORITY_MORE_QUOTA);
			}
			return RESPONSE_CODE_AUTHORITY_MORE_QUOTA;
		}else if(frozenAmount == -0.0005){
			if(vo != null){
				vo.setSwitchValue(7);
				vo.setMsg(RESPONSE_CODE_AUTHORITY_LESS_CREDIT);
			}
			return RESPONSE_CODE_AUTHORITY_LESS_CREDIT;
		}else if(frozenAmount == -0.0006){
			if(vo != null){
				vo.setSwitchValue(8);
				vo.setMsg(RESPONSE_CODE_AUTHORITY_PR_ERROR);
			}
			return RESPONSE_CODE_AUTHORITY_PR_ERROR;
		}else if(frozenAmount == -0.0007){//积分授权
			return RESPONSE_CODE_OK;
		}else if(frozenAmount == -0.0008){
			if(vo != null){
				vo.setSwitchValue(9);
				vo.setMsg(RESPONSE_CODE_PR_MISS_ERROR);
			}
			return RESPONSE_CODE_PR_MISS_ERROR;
		}else if(frozenAmount == -0.0009){
			if(vo != null){
				vo.setSwitchValue(10);
				vo.setMsg(RESPONSE_CODE_FUE_STATION_ERROR);
			}
			return RESPONSE_CODE_FUE_STATION_ERROR;
		}else{
			if(vo != null){
				vo.setSwitchValue(6);
				vo.setMsg(RESPONSE_CODE_AUTHORITY_MORE_CREDIT);
			}
			return RESPONSE_CODE_AUTHORITY_MORE_CREDIT;
		}
	}
	
	

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)
	public String cancelAuth(AuthorityCriteria criteria) throws Exception {
		int result = thawAmount(criteria);
		if(result>0){
			return RESPONSE_CODE_OK;
		}else if(result == -1){
			return RESPONSE_CODE_NOT_CHANGE_AUTHORITY;
		}else if(result == -2){
			return RESPONSE_CODE_NOT_EXIST_AUTHORITY;
		}
		return RESPONSE_CODE_SERVER_ERROR;
	}
	
	@Override
	public String getWxFuellingAuth(AuthorityCriteria criteria) throws Exception {
		if(!checkStationOnline(criteria.getStationId())){//申请站点是否在线
			return RESPONSE_CODE_STATION_OFFLINE;
		}
		if(transMap.containsKey(criteria.getFpId())){
			return RESPONSE_CODE_FP_BUSY;
		}
		//通知站端有授权
		MabDataTO mabDataTO = new MabDataTO();
		if(criteria.getType() == AuthType.FUL.getId()){
			mabDataTO.setWiz_1_dataType("F1");
			mabDataTO.setWiz_39_type(String.valueOf(AuthType.FUL.getId()));
			mabDataTO.setWiz_58_spareString("1");
		}else{
			mabDataTO.setWiz_1_dataType("F2");
			mabDataTO.setWiz_39_type(String.valueOf(AuthType.POI.getId()));
			mabDataTO.setWiz_58_spareString("0");
		}
		mabDataTO.setWiz_11_stationId(Integer.parseInt(criteria.getStationId()));
		mabDataTO.setWiz_12_fdId(Long.parseLong(criteria.getFpId()));
		mabDataTO.setWiz_13_memberId(Long.parseLong(criteria.getMemberId()));
		mabDataTO.setWiz_23_memberName(criteria.getMemberName());
		mabDataTO.setWiz_48_memberFrozenAmount(criteria.getMemberFrozenAmount());
		Channel channel = serviceManager.getStationConnectMap().get(criteria.getStationId());
		if(channel == null){
			log.error("this station offline, stationId="+criteria.getStationId());
			return RESPONSE_CODE_STATION_OFFLINE;
		}
		ChannelFuture cf = channel.writeAndFlush(getNettyMessage(mabDataTO, "fuellingAuthority", criteria.getStationId()));
		cf.addListener(
				new ChannelFutureListener() {
					@Override
					public void operationComplete(ChannelFuture future)
							throws Exception {
						if(!future.isSuccess()) {
							future.cause().printStackTrace();
							NettyInfoRecord.warnRecord("send getWxFuellingAuth fail");
						}else{
							NettyInfoRecord.infoRecord("send getWxFuellingAuth success");
						}
					}
				}
		);
		log.info("memberId="+criteria.getMemberId()+" used fuelling in WX");
		//挂起线程
		TransimissionVO vo = new TransimissionVO();
		transMap.put(criteria.getFpId(), vo);//创建了通知载体
		while(vo.getSwitchValue()==0){
			Thread.sleep(1000);
			if(vo.getCount()==5){//等待5秒之后方返回
				transMap.remove(criteria.getFpId());//清除载体，不能无限扩展内存
				vo = null;
				return RESPONSE_CODE_AUTHORITY_OVER_TIME;
			}
			vo.countPosition();
		}
		String result = vo.getMsg();
		log.info("memberId="+criteria.getMemberId()+" used fuelling in WX。。。。。。result="+result);
		transMap.remove(criteria.getFpId());//清除载体，不能无限扩展内存
		vo = null;
		return result;
	}
	
	/**
	 * 获取冻结金额
	 * @param to
	 * @param criteria
	 * @return
	 */
	private double frozenAmount(AuthorityTO to, AuthorityCriteria criteria){
		MemberCriteria memberCriteria = new MemberCriteria();
		memberCriteria.setHqId(criteria.getHqId());
		memberCriteria.setMemberId(criteria.getMemberId());
		memberCriteria.setCardNo(criteria.getCardNo());
		memberCriteria.setPhyCardNo(criteria.getPhysicalCardNo());
		memberCriteria.setVerificationCode(criteria.getVerificationCode());
		MemberTO memberTO = memberMapper.getMemberAmountInfo(memberCriteria);
		if(memberTO == null || memberTO.getStatus() != 1){
			return -0.0003;
		}
		if(StringUtils.isBlank(memberTO.getPrBinaryIds())){
			return -0.0008;
		}
		if(memberTO.getIsAllFue() != 1 && !memberTO.getFueStations().contains(criteria.getStationId())){
			return -0.0009;
		}
		FpCriteria fpCriteria = new FpCriteria();
		fpCriteria.setFpId(criteria.getFpId());
		FpTO fp = hqStationMapper.getFpById(fpCriteria);
		int prId = fp.getPrId();//油枪对应的油品Id
		if(!PRUtil.checkPRPermission(memberTO.getPrBinaryIds(), (long)prId)){
			return -0.0006;
		}
		to.setPrId(prId);
		MemberTO accountMemberTO = null;//资金帐号
		if(memberTO.getCompanyType() == CompanyType.GENERAL_PAY.getId()){//总帐支付
			MemberCriteria memberCriteria2 = new MemberCriteria();
			memberCriteria2.setHqId(criteria.getHqId());
			memberCriteria2.setMemberId(memberTO.getMemberAccountId());
			accountMemberTO = memberMapper.getMemberAmountInfo(memberCriteria2);
		}else{
			accountMemberTO = memberTO;
		}
		to.setMemberBalanceAmount(accountMemberTO.getAmount());
		if(accountMemberTO == null || accountMemberTO.getStatus() != 1){
			return -0.0003;
		}
		if(memberTO.getIsCheckStationAdminCard()!=null && memberTO.getIsCheckStationAdminCard() == 1){
			if(StringUtils.isBlank(criteria.getStationAdminVerifiId())){
				return -0.0001;
			}
			AdminTO admin = hqStationMapper.getAdminLoginInfoByAdminId(criteria.getStationAdminVerifiId(),
					criteria.getStationId());
			if(admin == null){
				return -0.0002;
			}
			to.setStationAdminVerifiId(criteria.getStationAdminId());
		}
		to.setMemberId(memberTO.getMemberId());
		to.setMemberName(memberTO.getMemberName());
		if(memberTO.getIsCheck() != null && memberTO.getIsCheck() == 1){//下放密码
			to.setFuellingPassword(memberTO.getFuellingPassword());
		}
		to.setIsCheckLicensePlate(memberTO.getIsCheckLicensePlate());
		to.setMemberLicencePlate(memberTO.getLicensePlate());
		to.setMemberAccountId(accountMemberTO.getMemberId());
		to.setMemberAccountName(accountMemberTO.getMemberName());
		
		//选择适合优惠
		PRConfigTO prTO = hqStationMapper.getPrConfig(prId);
		MemberGradeTO gradeTO = getGradeByMemberId(accountMemberTO.getMemberId());//已有汽/柴之分
		if(prTO == null || gradeTO == null){
			to.setSaleAmount(0.00);
			to.setAmountPoint(0);
		}else{
			if(prTO.getOilType() == 2){//柴油优惠
				to.setSaleAmount(gradeTO.getDieselSaleAmount());
				to.setAmountPoint(gradeTO.getPoint());//暂时使用汽油积分政策
			}else{
				to.setSaleAmount(gradeTO.getSaleAmount());
				to.setAmountPoint(gradeTO.getPoint());
			}
		}
		
		//计算冻结
		double frozenAmount = getFrozenAmount(memberTO,accountMemberTO);
		if(criteria.getMemberFrozenAmount() != null && criteria.getMemberFrozenAmount().doubleValue() > 0){//用户定量
			if(criteria.getMemberFrozenAmount().doubleValue() <= frozenAmount){
				frozenAmount = criteria.getMemberFrozenAmount().doubleValue();
			}else{
				return -0.0004;
			}
		}
		if(frozenAmount>0){
			//冻结金额
			accountMapper.addFrozenAmount(accountMemberTO.getMemberId(),frozenAmount);
			to.setMemberFrozenAmount(frozenAmount);
			authorityMapper.insertFuellingAutority(to);
		}else{
			if(accountMemberTO.getAmount()<=0){
				return -0.0005;
			}
		}
		return frozenAmount;
	}
	
	/**
	 * 解冻金额
	 * @param criteria
	 * @param stationId
	 */
	private int thawAmount(AuthorityCriteria criteria){
		List<AuthorityTO> list = authorityMapper.getFuellingAutorityTO(criteria);
		if(list.size() != 1){
			return -2;
		}
		AuthorityTO to = list.get(0);
		if(to.getStatus() != 0){
			return -1;
		}
		//解冻金额
		accountMapper.subFrozenAmount(to.getMemberAccountId(),to.getMemberFrozenAmount());
		return authorityMapper.cancelAuthority(to.getAuthorityId());
	}
	
	/**
	 * 根据公式 min[(余额+可透支金额-当前冻结金额),会员单笔限额，会员日总限额，会员月总限额] && [企业单笔限额，企业日总限额，企业月总限额]
	 * @param memberTO 被授权人信息
	 * @param amountMemberTO 扣款人信息，目前是总帐账号信息
	 * @return
	 */
	private double getFrozenAmount(MemberTO memberTO,MemberTO amountMemberTO){
		//计算余额部分 公式=余额+可透支金额-上次冻结金额
		double sumBalance = DecimalUtil.add(amountMemberTO.getAmount(),amountMemberTO.getMemberCreditLine());
		sumBalance = DecimalUtil.sub(sumBalance, amountMemberTO.getFrozenAmount());
		if(memberTO.getCompanyType() == CompanyType.GENERAL_PAY.getId()){//总帐判断
//			MemberCriteria memberCriteria = new MemberCriteria();
//			memberCriteria.setMemberId(amountMemberTO.getMemberId());
//			CompanyAmountLimitVO vo = memberMapper.getCompanyAmountLimit(memberCriteria);//获取公司限额，目前只限制总额
			double[] array = {sumBalance,memberTO.getMemberTimeUpLimit(),
					DecimalUtil.sub(memberTO.getMemberDailyUpLimit(),memberTO.getTotalDailyAmount()),//个人日余额限制
					DecimalUtil.sub(memberTO.getMemberMonthUpLimit(),memberTO.getTotalMonthAmount()),//个人月余额限制
//					vo.getCompanyTimeUpLimit(),vo.getCompanyDailyUpLimit(),vo.getCompanyMonthUpLimit() //企业限额
					};
			return Doubles.min(array);
		}else{
			double[] array = {sumBalance,memberTO.getMemberTimeUpLimit(),
					DecimalUtil.sub(memberTO.getMemberDailyUpLimit(),memberTO.getTotalDailyAmount()),//个人日余额限制
					DecimalUtil.sub(memberTO.getMemberMonthUpLimit(),memberTO.getTotalMonthAmount())};//个人月余额限制
			return Doubles.min(array);
		}
	}
	
	/**
	 * 获取会员等级
	 * @param memberId
	 * @return
	 */
	private MemberGradeTO getGradeByMemberId(String memberId){
		MemberCriteria criteria = new MemberCriteria();
		criteria.setMemberId(memberId);
		return memberMapper.getGradeByMemberId(criteria);
	}
}
